﻿using System;
using System.Collections.Generic;
using System.Text;
using PPT = Microsoft.Office.Interop.PowerPoint;
using Microsoft.Office.Core;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using TTServer.Objects;
using libUtilities;
using TTServer.Controller;


namespace TTServer
{
    public class PPTController
    {
        private static PPT.Application getPPTApplication()
        {
            PPT.Application pptApp = null;

            try
            {
                pptApp = new PPT.Application();
                pptApp.Visible = MsoTriState.msoTrue;
                pptApp.WindowState = PPT.PpWindowState.ppWindowMinimized;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

            return pptApp;
        }

        private static void cleanPPTApp(PPT.Application ppApp)
        {
            if (ppApp != null)
            {
                ppApp.Quit();
            }

            GC.Collect();
        }

        public bool checkPPTApplicationRun()
        {
            if (pptApplication != null)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /**
        * Đối với lớp PPController, ta chỉ cần tạo một Instance cho nó là đủ.
        * Mẫu Singleton được ứng dụng vào trường hợp này.
        */
        private static PPTController _instance = null;

        public static PPTController Instance
        {
            get
            {
                if (PPTController._instance == null)
                    PPTController._instance = new PPTController();
                return PPTController._instance;
            }
        }

        public static bool HasInstanceNotNull()
        {
            if (_instance != null)
            {
                return true;
            }
            return false;
        }

        /**
         * Sử dụng hàm CreateAnInstanceForClass() một mặt tạo một instance cho lớp
         * Mặt khác, gọi chạy powerpoint khi mà powerpoint vẫn chưa được khởi chạy.
         */
        public static PPTController CreateAnInstanceForClass()
        {
            try
            {
                PPTController._instance = new PPTController();
                _instance.pptApplication = PPTController.getPPTApplication();
                return PPTController._instance;
            }
            catch
            {
                return null;
            }
        }

        private PPTController()
        {
            //this.pptApplication = PPTController.getPPTApplication();
        }

        private PPT.Application pptApplication;

        private bool checkSlideShowWindowActivated()
        {
            //Kiểm tra này quá nghiêm ngặt, do có dùng DrawingScreen nên ta không dùng hàm này 

            if(pptApplication == null)
            {
                return false;
            }

            try
            {
                PPT.Presentation activePresentation = pptApplication.ActivePresentation;

                var tmp = activePresentation.SlideShowWindow.Active;
                return tmp == MsoTriState.msoTrue;
            }
            catch
            {
                return false;
            }
        }

        public int checkSlideShowActivated()
        {
            //Kiểm tra đang chiếu slideshow

            if (pptApplication == null)
            {
                return 0;
            }

            try
            {
                PPT.Presentation activePresentation = pptApplication.ActivePresentation;

                var tmp = activePresentation.SlideShowWindow.IsFullScreen;
                return (tmp == MsoTriState.msoTrue) ? 1 : 0;
            }
            catch
            {
                return 0;
            }
        }

        public int SetActivePresentationIndex(int index)
        {
            if (pptApplication == null)
            {
                return 0;
            }

            try
            {
                int idx = index + 1;

                if (idx >= 1 && idx <= pptApplication.Presentations.Count)
                {
                    for (int j = 1; j <= pptApplication.Windows.Count; j++)
                    {
                        if (pptApplication.Windows[j].Presentation == pptApplication.Presentations[idx])
                        {
                            pptApplication.Windows[j].Activate();
                        }
                    }

                    return 1;
                }
                else
                {
                    return 0;
                }
            }
            catch
            {
                return 0;
            }
        }

        public String[] GetPresentationNames()
        {
            if (pptApplication == null)
            {
                return null;
            }

            try
            {
                int n = this.pptApplication.Presentations.Count;

                String[] strs = new String[n];

                for (int i = 0; i < n; i++)
                {
                    string name = this.pptApplication.Presentations[i + 1].Name;
                    strs[i] = name;
                }

                return strs;
            }
            catch
            {
                return null;
            }
        }

        public String GetActivePresentationName()
        {
            if (pptApplication == null)
            {
                return null;
            }

            try
            {
                string name = this.pptApplication.ActivePresentation.Name;

                return name;
            }
            catch
            {
                return null;
            }
        }

        public int GetWindowRelationship(ref String [] presentationNames, ref int activeIndex)
        {
            presentationNames = null;

            activeIndex = -1;

            if (pptApplication == null)
            {
                return 0;
            }

            try
            {
                int n = this.pptApplication.Windows.Count;

                String[] strs = new String[n];

                for (int i = 0; i < n; i++)
                {
                    strs[i] = this.pptApplication.Windows[i + 1].Presentation.Name;

                    if (this.pptApplication.Windows[i + 1] == this.pptApplication.ActiveWindow)
                    {
                        activeIndex = i;
                    }

                }

                presentationNames = strs;

                return 1;
            }
            catch
            {
                return 0;
            }
        }

        public int ActivateWindow(int index_0b, String presentationName)
        {
            try
            {

                if (pptApplication == null)
                {
                    return 0;
                }

                int index_1b = index_0b + 1;

                if (1 <= index_1b && index_1b <= this.pptApplication.Windows.Count)
                {
                    if (this.pptApplication.Windows[index_1b].Presentation.Name == presentationName)
                    {
                        this.pptApplication.Windows[index_1b].Activate();

                        return 1;
                    }
                }
            }
            catch
            { 
            
            }

            return 0;
        }

        public int CheckNoPresentationOpen()
        {
            if (pptApplication == null)
            {
                return -1;
            }

            try
            {
                if (this.pptApplication.Presentations.Count == 0)
                    return 1;
                else
                    return 0;
            }
            catch{
                return -1;
            }
        }

        public int CloseActiveWindow()
        {
            if (pptApplication == null)
            {
                return 0;
            }

            try
            {
                this.pptApplication.ActiveWindow.Close();
                return 1;
            }
            catch
            {
                return 0;
            }
        }

        public int CloseByIndex(int index)
        {
            if (pptApplication == null)
            {
                return 0;
            }

            try
            {
                var win = pptApplication.Windows[index + 1];
                win.Close();
                
                return 1;
            }
            catch
            {
                return 0;
            }
        }

        public int CloseAll()
        {
            if (pptApplication == null)
            {
                return 0;
            }

            try
            {
                for (int i = pptApplication.Windows.Count; i >= 1; i--)
                {
                    var win = pptApplication.Windows[i];
                    win.Close();
                }

                return 1;
            }
            catch
            {
                return 0;
            }
        }

        public int Open(String filePath)
        {
            if (pptApplication == null)
            {
                return 0;
            }

            try
            {
                this.Maximize();

                var objPresSet = pptApplication.Presentations;
                string strPath = filePath;
                var objPres = objPresSet.Open(strPath,
                    MsoTriState.msoFalse, MsoTriState.msoFalse, MsoTriState.msoTrue);

                objPres.Windows[1].Activate();

                return 1;
            }
            catch
            {
                return 0;
            }
        }

        public int IsFirstSlide()
        {
            if (pptApplication == null)
            {
                return 0;
            }

            try
            {
                int index = this.pptApplication.ActivePresentation.SlideShowWindow.View.Slide.SlideIndex;

                // One-based Collection
                if (1 == index)
                    return 1;
                return 0;
            }
            catch (Exception ex)
            {
                //MessageBox.Show(ex.Message);
                return 0;
            }
        }

        public int IsEndingSlide()
        {
            if (pptApplication == null)
            {
                return 0;
            }

            try
            {

                int index = this.pptApplication.ActivePresentation.SlideShowWindow.View.Slide.SlideIndex;

                // One-based Collection
                if (this.pptApplication.ActivePresentation.Slides.Count == index)
                    return 1;
                return 0;
            }
            catch (Exception ex)
            {
                //MessageBox.Show(ex.Message);
                return 0;
            }
        }

        public int Start()
        {
            try
            {
                if (pptApplication == null)
                {
                    return 0;
                }

                if (this.pptApplication.ActivePresentation == null)
                    return 0;

                //Lời gọi hàm này sẽ block cho tới khi PPT chuyển tới slideshow thành công
                this.pptApplication.ActivePresentation.SlideShowSettings.Run();
                
                int hdl = this.pptApplication.ActivePresentation.SlideShowWindow.HWND;

                Org.Vesic.WinForms.WinApi.SetWinFullScreen((IntPtr) hdl);
                

                return 1;
            }
            catch
            {
                return 0;
            }
        }

        public void Activate()
        {
            if (pptApplication == null)
            {
                return;
            }

            try
            {
                this.pptApplication.ActivePresentation.SlideShowWindow.Activate();
            }
            catch
            {

            }
        }

        public int PrevSlide()
        {
            if (pptApplication == null)
            {
                return 0;
            }

            try
            {
                this.pptApplication.ActivePresentation.SlideShowWindow.Activate();

                this.pptApplication.ActivePresentation.SlideShowWindow.View.Previous();

                return 1;
            }
            catch
            {
                return 0;
            }
        }

        public int NextSlide()
        {
            if (pptApplication == null)
            {
                return 0;
            }

            try
            {
                this.pptApplication.ActivePresentation.SlideShowWindow.Activate();
                this.pptApplication.ActivePresentation.SlideShowWindow.View.Next();

                return 1;
            }
            catch
            {
                return 0;
            }
        }

        public int GoToSlide(int idx)
        {
            if (pptApplication == null)
            {
                return 0;
            }

            try
            {
                this.pptApplication.ActivePresentation.SlideShowWindow.Activate();
                this.pptApplication.ActivePresentation.SlideShowWindow.View.GotoSlide(idx);

                return 1;
            }
            catch
            {
                return 0;
            }
        }

        public int GetCurrentSlideIndexShowing()
        {
            if (pptApplication == null)
            {
                return 0;
            }

            try
            {
                this.pptApplication.ActivePresentation.SlideShowWindow.Activate();

                int result = this.pptApplication.ActivePresentation.SlideShowWindow.View.Slide.SlideIndex;

                return result;
            }
            catch
            {
                return 0;
            }
        }

        public int EndShow()
        {
            if (pptApplication == null)
            {
                return 0;
            }

            try
            {
                if (this.checkSlideShowActivated() == 1)
                {
                    this.pptApplication.ActivePresentation.SlideShowWindow.Activate();
                    this.pptApplication.ActivePresentation.SlideShowWindow.View.Exit();
                }
                return 1;
            }
            catch
            {
                return 0;
            }
        }

        public int Minimize()
        {
            if (pptApplication == null)
            {
                return 0;
            }

            try
            {
                PPTController.Instance.pptApplication.WindowState = PPT.PpWindowState.ppWindowMinimized;
                return 1;
            }
            catch
            {
                return 0;
            }
        }

        public int Maximize()
        {
            if (pptApplication == null)
            {
                return 0;
            }

            try
            {
                PPTController.Instance.pptApplication.WindowState = PPT.PpWindowState.ppWindowMaximized;
                return 1;
            }
            catch
            {
                return 0;
            }
        }

        public int Normalize()
        {
            if (pptApplication == null)
            {
                return 0;
            }

            try
            {
                PPTController.Instance.pptApplication.WindowState = PPT.PpWindowState.ppWindowNormal;
                return 1;
            }
            catch
            {
                return 0;
            }
        }

        public int LaunchPowerpoint()
        {
            try
            {
                this.pptApplication = PPTController.getPPTApplication();

                this.Maximize();

                return 1;
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
                return 0;
            }
        }

        public int QuitPowerpoint()
        {
            // Chỉ nên sử dụng khi lúc thoát chương trình
            // Khi chuong trinh mo hai window thì chưa thoát ngay, 1 window thì thoát ngay
            // Khi truoc do hai cua so la chuong trinh khac mo thi thoat ngay

            if (pptApplication == null)
            {
                pptApplication = PPTController.getPPTApplication();


                if (pptApplication == null)
                {
                    return 0;
                }
            }

            try
            {
                try
                {
                    PPTController.Instance.CloseAll();
                }
                catch
                { 
                
                }

                //PPTController.Instance.pptApplication.Quit();

                PPTController.cleanPPTApp(PPTController.Instance.pptApplication);

                return 1;
            }
            catch
            {
                return 0;
            }

        }

        public int GetTheNumberOfSildes()
        {
            if (pptApplication == null)
            {
                return 0;
            }

            try
            {
                int n = this.pptApplication.ActivePresentation.Slides.Count;

                return n;
            }
            catch
            {
                return 0;
            }
        }

        public Image GetSlideImage()
        {
            if (pptApplication == null)
            {
                return null;
            }

            try
            {
                //Do có dùng DrawingScreen nên không dùng điều kiện khắc khe này.
                //if (!bIsActive) return null;
                
                if (checkSlideShowActivated() == 0) 
                    return null;

                var w = this.pptApplication.ActivePresentation.SlideShowWindow;
                return ImageUtils.CaptureWindow(new IntPtr(w.HWND));
            }
            catch
            {
                return null;
            }
        }

        public void Draw(int[] points, Size ScreenSize)
        {
            //if (!bIsActive) return;
            
            if (checkSlideShowActivated() == 0) 
                return;

            var Presentation = pptApplication.ActivePresentation;

            //Biến v sẽ tham chiếu tới một instance của lớp SlideShowView
            var v = Presentation.SlideShowWindow.View;

            //1366 x 768
            //float height = 768;

            //float height = Presentation.SlideShowWindow.Height; //576.0
            //float width = Presentation.SlideShowWindow.Width; //1024.5

            float height = Presentation.PageSetup.SlideHeight;
            float width = Presentation.PageSetup.SlideWidth;

            // Fixed size??
            //SizeF s = new SizeF(800, 600);

            //SizeF s = new SizeF(800 * (height/600), height);

            SizeF s = new SizeF(width, height);

            for (int i = 2; i < points.Length; i += 2)
            {
                var startX = (float)points[i - 2] / (float)ScreenSize.Width * s.Width;
                var startY = (float)points[i - 1] / (float)ScreenSize.Height * s.Height;
                var endX = (float)points[i - 0] / (float)ScreenSize.Width * s.Width;
                var endY = (float)points[i + 1] / (float)ScreenSize.Height * s.Height;

                v.DrawLine(startX, startY, endX, endY);
            }
        }

        public void Draw_2()
        {
            if (checkSlideShowActivated() == 0)
                return;

            var v = this.pptApplication.ActivePresentation.SlideShowWindow.View;

            v.DrawLine(0, 0, 400, 400);

            v.DrawLine(500, 500, 600, 600);

            v.DrawLine(540, 0, 540, 540);

            v.DrawLine(720, 0, 720, 540);
        }

        public void exportToPNG()
        {
            //int count = 1;

            //foreach (PPT.Slide pptSlide in Presentation.Slides)
            //{
            //    pptSlide.Export("C://slideImages//" + count.ToString("00") + ".jpg", "JPG", 800, 600);
            //    count++;
            //}

            this.pptApplication.ActivePresentation.Slides[1].Export(@"C:\slideImages\" + 1.ToString("00") + ".png",
                "PNG", 2048, 1536);

            //Presentation.Slides[1].Export(@"C:\slideImages\" + 1.ToString("00") + ".bmp", "BMP",
            //   3200, 2400 );

            //Presentation.Slides[1].Export(@"C:\slideImages\" + 1.ToString("00") + ".bmp", "BMP");
        }

        public bool checkTheWindowIsSlideShow(IntPtr pointer)
        {
            try
            {
                if (pointer == IntPtr.Zero)
                {
                    return false;
                }

                String windowCaption = USER32.GetText(pointer);

                if (windowCaption != "Slide Show")
                {
                    return false;
                }

                /////////////////////////////////////////////////////////////////////
                int nRet;

                StringBuilder ClassName = new StringBuilder(255);

                nRet = USER32.GetClassName(pointer, ClassName, ClassName.Capacity);
                if (nRet != 0)
                {
                    return (string.Compare(ClassName.ToString(), "paneClassDC") == 0);
                }
                else
                {
                    return false;
                }
                //////////////////////////////////////////////////////////////////////
            }
            catch
            {
                return false;
            }
        }

        private IntPtr hwndSlideShow = IntPtr.Zero;

        public IntPtr getSlideShowHWnd()
        {
            try
            {
                if (checkTheWindowIsSlideShow(hwndSlideShow))
                {
                    return hwndSlideShow;
                }

                IntPtr hSlideShowWindow = new IntPtr(this.pptApplication.ActivePresentation.SlideShowWindow.HWND);

                List<IntPtr> intPtrList = USER32.GetChildWindows(hSlideShowWindow);

                int nList = intPtrList.Count;

                for (int i = 0; i < nList; i++)
                {
                    IntPtr hWnd = intPtrList[i];

                    if (checkTheWindowIsSlideShow(hWnd))
                    {
                        this.hwndSlideShow = hWnd;
                        return hWnd;
                    }
                }

                return IntPtr.Zero;
            }
            catch
            {
                return IntPtr.Zero;
            }
        }

        public bool SendSlideShowClick(double x, double y)
        {
            try
            {
                if (pptApplication == null)
                {
                    return false;
                }

                IntPtr hWnd = this.getSlideShowHWnd();

                if (hWnd != IntPtr.Zero)
                {
                    this.pptApplication.ActivePresentation.SlideShowWindow.View.PointerType
                        = PPT.PpSlideShowPointerType.ppSlideShowPointerArrow;

                    Size size = new Size(Screen.PrimaryScreen.Bounds.Width,
                               Screen.PrimaryScreen.Bounds.Height);

                    int lcX = (int)(x * size.Width);
                    int lcY = (int)(y * size.Height);

                    int LParam = WinAPIUtils.MakeLParam(lcX, lcY);

                    WinAPIUtils.SendMessage(hWnd, WM_SETFOCUS, new IntPtr(0), new IntPtr(0));
                    WinAPIUtils.PostMessage(hWnd, 0x201, new IntPtr(0), new IntPtr(LParam));
                    WinAPIUtils.PostMessage(hWnd, 0x202, new IntPtr(0), new IntPtr(LParam));

                    return true;
                }

                return false;
            }
            catch
            {
                return false;
            }
        }

        public bool SendSlideShowClick2(double x, double y)
        {
            try
            {
                PPT.TimeLine timeLine = this.pptApplication.ActivePresentation.Slides[1].TimeLine;
                PPT.Sequence mainSequence = timeLine.MainSequence;


                foreach (PPT.Effect eff in mainSequence)
                {
                    float a = eff.Timing.Duration;
                    a = a; 
                }

                PPT.Sequences interactiveSequences = timeLine.InteractiveSequences;

                foreach (PPT.Sequence seq in interactiveSequences)
                {
                    foreach (PPT.Effect eff in seq)
                    {
                        float a = eff.Timing.Duration;
                        a = a;
                    }
                }
                

                IntPtr hWnd = this.getSlideShowHWnd();

                if (hWnd != IntPtr.Zero)
                {
                    

                    int lcX = (int)(x * 1366);
                    int lcY = (int)(y * 768);

                    int LParam = WinAPIUtils.MakeLParam(lcX, lcY);

                    WinAPIUtils.SendMessage(hWnd, WM_SETFOCUS, new IntPtr(0), new IntPtr(0));
                    WinAPIUtils.PostMessage(hWnd, 0x201, new IntPtr(0), new IntPtr(LParam));
                    WinAPIUtils.PostMessage(hWnd, 0x202, new IntPtr(0), new IntPtr(LParam));

                    return true;
                }

                return false;
            }
            catch
            {
                return false;
            }
        }

        public const int WM_KEYDOWN = 0x0100;
        public const int WM_KEYUP   = 0x0101;
        public const int WM_SETFOCUS = 0x0007;

        public const int VK_B = 0x42;
        public const int VK_W = 0x57;

        public bool SendBKeyToSlideShow()
        {
            try
            {
                IntPtr hWnd = this.getSlideShowHWnd();

                if (hWnd != IntPtr.Zero)
                {
                    {
                        int nVirKey = VK_B;
                        int cRepeat = 1;
                        int ScanCode = 0x30;
                        int fExtended = 0;
                        int fRepeat = 0;
                        int fUp = 0;

                        int LParam = (cRepeat) | (ScanCode << 16)
                            | (fExtended << 24) | (fRepeat << 30) | (fUp << 31);
                        
                        WinAPIUtils.SendMessage(hWnd, WM_SETFOCUS, new IntPtr(0), new IntPtr(0));
                   
                        WinAPIUtils.PostMessage(hWnd, WM_KEYDOWN, new IntPtr(nVirKey), new IntPtr(LParam));
                    }

                    {
                        int nVirKey = VK_B;
                        int cRepeat = 1;
                        int ScanCode = 0x30;
                        int fExtended = 0;
                        int fRepeat = 1;
                        int fUp = 1;

                        int LParam = (cRepeat) | (ScanCode << 16)
                           | (fExtended << 24) | (fRepeat << 30) | (fUp << 31);

                        WinAPIUtils.PostMessage(hWnd, WM_KEYUP, new IntPtr(nVirKey), new IntPtr(LParam));
                    }

                    return true;
                }

                return false;
            }
            catch
            {
                return false;
            }
        }

        public bool SendWKeyToSlideShow()
        {
            try
            {
                IntPtr hWnd = this.getSlideShowHWnd();

                if (hWnd != IntPtr.Zero)
                {
                    {
                        int nVirKey = VK_W;
                        int cRepeat = 1;
                        int ScanCode = 0x11;
                        int fExtended = 0;
                        int fRepeat = 0;
                        int fUp = 0;

                        int LParam = (cRepeat) | (ScanCode << 16)
                            | (fExtended << 24) | (fRepeat << 30) | (fUp << 31);

                        WinAPIUtils.SendMessage(hWnd, WM_SETFOCUS, new IntPtr(0), new IntPtr(0));

                        WinAPIUtils.PostMessage(hWnd, WM_KEYDOWN, new IntPtr(nVirKey), new IntPtr(LParam));
                    }

                    {
                        int nVirKey = VK_W;
                        int cRepeat = 1;
                        int ScanCode = 0x11;
                        int fExtended = 0;
                        int fRepeat = 1;
                        int fUp = 1;

                        int LParam = (cRepeat) | (ScanCode << 16)
                           | (fExtended << 24) | (fRepeat << 30) | (fUp << 31);

                        WinAPIUtils.PostMessage(hWnd, WM_KEYUP, new IntPtr(nVirKey), new IntPtr(LParam));
                    }

                    return true;
                }

                return false;
            }
            catch
            {
                return false;
            }
        }

        public List<CSlideData> GetAllSlideNumberAndSlideTitle()
        {

            if (pptApplication == null)
            {
                return null;
            }

            List<CSlideData> list = new List<CSlideData>();

            try
            {
                foreach (PPT.Slide s in this.pptApplication.ActivePresentation.Slides)
                {
                    CSlideData data = new CSlideData();

                    if (s.Shapes.HasTitle == MsoTriState.msoTrue)
                    {
                        data.slideTitle = s.Shapes.Title.TextFrame.TextRange.Text;
                    }
                    else
                    {
                        data.slideTitle = "";
                    }

                    data.slideIndex = s.SlideIndex;

                    list.Add(data);
                }
            }
            catch
            {
                return null;
            }

            return list;
        }

    }
}
